package org.jeecg.modules.sistersophie.facade.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lowagie.text.DocumentException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.modules.sistersophie.config.ChangeDirectionEnums;
import org.jeecg.modules.sistersophie.config.PaymentStatusEnums;
import org.jeecg.modules.sistersophie.constans.GlobalConstans;
import org.jeecg.modules.sistersophie.entity.*;
import org.jeecg.modules.sistersophie.facade.AccountTransactionFacade;
import org.jeecg.modules.sistersophie.facade.CourseStudentFacade;
import org.jeecg.modules.sistersophie.facade.InvoiceFacade;
import org.jeecg.modules.sistersophie.model.dto.CourseStudentDTO;
import org.jeecg.modules.sistersophie.model.request.InvoiceAddRequest;
import org.jeecg.modules.sistersophie.model.request.InvoicePaymentCompletedRequest;
import org.jeecg.modules.sistersophie.model.vo.CourseStudentSearchVO;
import org.jeecg.modules.sistersophie.model.vo.InvoiceFileCourseItemVO;
import org.jeecg.modules.sistersophie.model.vo.InvoiceFileStudentVO;
import org.jeecg.modules.sistersophie.model.vo.InvoiceFileVO;
import org.jeecg.modules.sistersophie.service.ICourseInfoService;
import org.jeecg.modules.sistersophie.service.ICourseStudentInfoService;
import org.jeecg.modules.sistersophie.service.IInvoiceInfoService;
import org.jeecg.modules.sistersophie.util.FileUtil;
import org.jeecg.modules.sistersophie.util.PdfUtils;
import org.jeecg.modules.sistersophie.util.VelocityUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class InvoiceFacadeService implements InvoiceFacade {

    @Autowired
    private IInvoiceInfoService invoiceInfoService;

    @Autowired
    private StudentFacadeService facadeService;

    @Autowired
    private CourseStudentFacade courseStudentFacade;

    @Autowired
    private ICourseStudentInfoService iCourseStudentInfoService;

    @Autowired
    private AccountTransactionFacade accountTransactionFacade;

    @Autowired
    private ICourseInfoService courseInfoService;

    @Autowired
    private ISysBaseAPI sysBaseAPI;

    private String templetPath = "/templates/1v1.vm";

    public void sendEmail(String invoiceId,String paymentMethod){
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        VelocityUtil velocityUtil = new VelocityUtil();
        Map<String,Object> contractParam = loadFileData(invoiceId,paymentMethod);
        String invoiceContent = velocityUtil.convertTemplet(templetPath,contractParam);
        InvoiceInfo invoiceInfo = invoiceInfoService.getById(invoiceId);
        StudentInfo studentInfo = facadeService.selectById(invoiceInfo.getStudentId());
        //invoiceInfo.setStatus(PaymentStatusEnums.ING_PAYMENT.getStatus());
        invoiceInfo.setPaymentMethod(paymentMethod);
        invoiceInfo.setInvoiceStatus(10);
        invoiceInfo.setInvoiceTime(new Date());
        invoiceInfo.setUpdateTime(new Date());
        invoiceInfo.setUpdateName(sysUser.getUsername());
        invoiceInfoService.updateById(invoiceInfo);
        if(StringUtils.isBlank(studentInfo.getEmail())){
            throw new RuntimeException(" Student email information is empty ");
        }
        sysBaseAPI.sendEmailMsg(studentInfo.getEmail(),"invoice",invoiceContent);
    }

    public void downLoadPdf(ModelAndView mv,String invoiceId){
        Map<String,Object> data =  this.loadFileData(invoiceId,null);
        mv.addObject("invoice",data.get("invoice"));
        mv.addObject("student",data.get("student"));
        mv.addObject("itemList",data.get("itemList"));
        mv.addObject("comments",data.get("comments"));
        mv.addObject("paymentMethod",data.get("paymentMethod"));
        mv.addObject("invoiceId",data.get("invoiceId"));
    }

    private Map<String,Object> loadFileData(String invoiceId,String paymentMethod){
        Map<String,Object> resMap = new HashMap<>();
        //加载invoice 信息
        InvoiceInfo invoiceInfo = invoiceInfoService.getById(invoiceId);
        if(invoiceInfo == null){
            throw new RuntimeException(" invoice info is null ");
        }
        if(StringUtils.isBlank(paymentMethod)){
            paymentMethod = invoiceInfo.getPaymentMethod();
        }
        if(StringUtils.isBlank(paymentMethod)){
            paymentMethod = "E-transfer";
        }
        //加载 student Info
        Integer studentId = invoiceInfo.getStudentId();
        StudentInfo studentInfo = facadeService.selectById(studentId);
        if(studentInfo == null){
            throw new RuntimeException(" student info is null ");
        }
        //加载课程列表
        List<CourseStudentInfo> courseStudentList  = courseStudentFacade.selectByInvoiceId(invoiceInfo.getId(),null);
        if(CollectionUtils.isEmpty(courseStudentList)){
            throw new RuntimeException(" course Student List is Null ");
        }
        //组装VO对象
        InvoiceFileVO invoiceFileVO = new InvoiceFileVO();
        invoiceFileVO.setDate(DateUtil.formatDate(new Date()));
        if(StringUtils.isNotBlank(invoiceInfo.getCurrency())){
            invoiceFileVO.setCurrency(invoiceInfo.getCurrency().split("-")[0]);
        }
        if(invoiceInfo.getCurrencyAmount() != null){
            String  currencyAmount = NumberUtil.decimalFormat(GlobalConstans.DECIMARPATTERN, invoiceInfo.getCurrencyAmount());
            invoiceFileVO.setCurrencyAmount(currencyAmount);
        }

        resMap.put("invoice",invoiceFileVO);
        String chineseName = studentInfo.getChineseName();
        StringBuffer buffer = new StringBuffer();
        buffer.append(studentInfo.getFirstName()).append(" ").append(studentInfo.getLastName());
        if(StringUtils.isNotBlank(chineseName)){
            buffer.append("(").append(chineseName).append(")");
        }
        InvoiceFileStudentVO studentVO = new InvoiceFileStudentVO();
        studentVO.setName(buffer.toString());
        studentVO.setEmail(studentInfo.getEmail());
        if(StringUtils.isNotBlank(studentInfo.getMobilePrefix()) && StringUtils.isNotBlank(studentInfo.getMobileNumber())){
            String phone = "+"+studentInfo.getMobilePrefix()+studentInfo.getMobileNumber();
            studentVO.setPhone(phone);
        }
        studentVO.setAddress(studentInfo.getAddress());
        resMap.put("student",studentVO);
        List<InvoiceFileCourseItemVO> itemList = new ArrayList<>();
        for(CourseStudentInfo info : courseStudentList){
            InvoiceFileCourseItemVO itemVO = new InvoiceFileCourseItemVO();
            CourseInfo courseInfo = courseInfoService.getById(info.getCourseId());
            if(courseInfo == null){
                throw new RuntimeException(" course info is Null ");
            }
            itemVO.setCourseName(courseInfo.getName());
            itemVO.setItemName(courseInfo.getGrade() + "  " + courseInfo.getCategoryName());
            itemVO.setSection(String.valueOf(courseInfo.getHours()));
            itemVO.setPrice(GlobalConstans.CURRENCY+ NumberUtil.decimalFormat(GlobalConstans.DECIMARPATTERN,info.getPrice()));
            itemList.add(itemVO);
        }
        InvoiceFileCourseItemVO sumItem = new InvoiceFileCourseItemVO();
        sumItem.setCourseName("");
        sumItem.setItemName("");
        sumItem.setSection("Sum");
        sumItem.setPrice(GlobalConstans.CURRENCY+ NumberUtil.decimalFormat(GlobalConstans.DECIMARPATTERN, invoiceInfo.getAmount()));
        itemList.add(sumItem);

        if(invoiceInfo.getDiscountAmount() != null && invoiceInfo.getDiscountAmount().compareTo(BigDecimal.ZERO) > 0){
            InvoiceFileCourseItemVO disCountItem = new InvoiceFileCourseItemVO();
            disCountItem.setCourseName("");
            disCountItem.setItemName("");
            disCountItem.setSection("Discount");
            disCountItem.setPrice("-" + GlobalConstans.CURRENCY+ NumberUtil.decimalFormat(GlobalConstans.DECIMARPATTERN, invoiceInfo.getDiscountAmount()));
            itemList.add(disCountItem);
        }
        InvoiceFileCourseItemVO taxRateItem = new InvoiceFileCourseItemVO();
        taxRateItem.setCourseName("");
        taxRateItem.setItemName("");
        taxRateItem.setSection("Tax Rate");
        taxRateItem.setPrice(invoiceInfo.getTax() + "%");
        itemList.add(taxRateItem);

        InvoiceFileCourseItemVO taxDueItem = new InvoiceFileCourseItemVO();
        taxDueItem.setCourseName("");
        taxDueItem.setItemName("");
        taxDueItem.setSection("Tax due");
        taxDueItem.setPrice(GlobalConstans.CURRENCY+ NumberUtil.decimalFormat(GlobalConstans.DECIMARPATTERN, invoiceInfo.getTaxAmount()));
        itemList.add(taxDueItem);

        InvoiceFileCourseItemVO otherItem = new InvoiceFileCourseItemVO();
        otherItem.setCourseName("");
        otherItem.setItemName("");
        otherItem.setSection("Other");
        itemList.add(otherItem);
        if(invoiceInfo.getCredit() != null && invoiceInfo.getCredit() > 0){
            otherItem.setPrice("-" + GlobalConstans.CURRENCY+ NumberUtil.decimalFormat(GlobalConstans.DECIMARPATTERN, invoiceInfo.getCredit()));
        }else{
            otherItem.setPrice("$0");
        }

        //信用卡 2.56% 支付宝/微信 1.56%
        String creditPayment = "Credit";
        String aliWechatPayment = "AliWeChat";
        if(StringUtils.isNotBlank(paymentMethod) && (paymentMethod.equals(creditPayment) || paymentMethod.equals(aliWechatPayment))){
            BigDecimal serviceFee = BigDecimal.ZERO;
            if(paymentMethod.equals(creditPayment)){
                serviceFee = invoiceInfo.getInvoiceAmount().multiply(new BigDecimal("0.0256"));
            }else if(paymentMethod.equals(aliWechatPayment)){
                serviceFee = invoiceInfo.getInvoiceAmount().multiply(new BigDecimal("0.0155"));
            }
            serviceFee = serviceFee.setScale(2,BigDecimal.ROUND_UP);
            invoiceInfo.setInvoiceAmount(invoiceInfo.getInvoiceAmount().add(serviceFee));

            InvoiceFileCourseItemVO totalItem = new InvoiceFileCourseItemVO();
            totalItem.setCourseName("");
            totalItem.setItemName("");
            totalItem.setSection("Service Fee");
            totalItem.setPrice(GlobalConstans.CURRENCY+ NumberUtil.decimalFormat(GlobalConstans.DECIMARPATTERN, serviceFee));
            itemList.add(totalItem);
        }
        InvoiceFileCourseItemVO totalItem = new InvoiceFileCourseItemVO();
        totalItem.setCourseName("");
        totalItem.setItemName("");
        totalItem.setSection("Total");
        totalItem.setPrice(GlobalConstans.CURRENCY+ NumberUtil.decimalFormat(GlobalConstans.DECIMARPATTERN, invoiceInfo.getInvoiceAmount()));
        itemList.add(totalItem);

        if(StringUtils.isNotBlank(invoiceFileVO.getCurrency()) && StringUtils.isNotBlank(invoiceFileVO.getCurrencyAmount())){
            InvoiceFileCourseItemVO currencyItem = new InvoiceFileCourseItemVO();
            currencyItem.setCourseName("");
            currencyItem.setItemName("");
            currencyItem.setSection("Total");
            currencyItem.setPrice( invoiceFileVO.getCurrencyAmount() + "  " + invoiceFileVO.getCurrency());
            itemList.add(currencyItem);
        }
        resMap.put("itemList",itemList);
        if(StringUtils.isBlank(invoiceInfo.getRemarks())){
            invoiceInfo.setRemarks("");
        }
        resMap.put("comments",invoiceInfo.getRemarks());
        resMap.put("paymentMethod",paymentMethod);
        resMap.put("invoiceId",invoiceInfo.getId());
        return resMap;
    }

    public void generatePdfFile() throws IOException, DocumentException {
        String templetPath = "/templates/1v1.vm";
        VelocityUtil velocityUtil = new VelocityUtil();
        Map<String,Object> contractParam = new HashMap<>();
        String contractContent = velocityUtil.convertTemplet(templetPath,contractParam);
        String tmpPath = "/Users/zhongquan/Documents/zq/在线教育/html";
        File tempDir = new File(tmpPath);
        if(!tempDir.exists()){
            tempDir.mkdir();
        }
        FileUtil fileUtil = new FileUtil();
        StringBuffer filePath = new StringBuffer();
        filePath.append(tempDir).append("/").append("1v1.pdf");
        fileUtil.createPDF(contractContent,filePath.toString());

        StringBuffer filePath1 = new StringBuffer();
        filePath1.append(tempDir).append("/").append("1v1-1.pdf");
        FileOutputStream fileOutputStream = new FileOutputStream(filePath1.toString());
        PdfUtils.writeStringToOutputStreamAsPDF(contractContent,fileOutputStream);
        fileOutputStream.close();
        sysBaseAPI.sendEmailMsg("quan.zhong@weimob.com","invoice",contractContent);
    }

    @Transactional
    public void deleteInvoice(String id){
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        InvoiceInfo invoiceInfo =  invoiceInfoService.getById(Integer.parseInt(id));
        if(invoiceInfo == null){
            throw new RuntimeException(" invoice info is null ");
        }
        if(invoiceInfo.getStatus().intValue() == PaymentStatusEnums.DONE_PAYMENT.getStatus()){
            throw new RuntimeException(" The payment has been completed and cannot be deleted ");
        }
        List<CourseStudentInfo> courseStudentList  = courseStudentFacade.selectByInvoiceId(invoiceInfo.getId(),PaymentStatusEnums.ING_PAYMENT.getStatus());
        if(CollectionUtils.isEmpty(courseStudentList)){
            throw new RuntimeException(" course Student List is Null ");
        }
        boolean isDel = true;
        for(CourseStudentInfo info : courseStudentList){
            if(info.getPayStatus().intValue() == PaymentStatusEnums.DONE_PAYMENT.getStatus()){
                isDel = false;
                break;
             }
            info.setPayStatus(PaymentStatusEnums.NON_PAYMENT.getStatus());
            info.setPayTime(null);
            info.setDescription(null);
            info.setInvoiceId(null);
            info.setActualPrice(info.getPrice());
            info.setUpdateTime(new Date());
            info.setUpdateName(sysUser.getUsername());
        }
        if(!isDel){
            throw new RuntimeException(" The payment has been completed and cannot be deleted ");
        }
        if(invoiceInfo.getCredit() != null && invoiceInfo.getCredit() > 0){
            AccountTransaction accountTransaction = new AccountTransaction();
            accountTransaction.setStudentId(invoiceInfo.getStudentId());
            accountTransaction.setChangeAmount(new BigDecimal(String.valueOf(invoiceInfo.getCredit())));
            accountTransaction.setChangeDirection(ChangeDirectionEnums.TYPE_UNFREE.getType());
            String remark="invoice:"+invoiceInfo.getId() + " unfreeze";
            accountTransactionFacade.changeCredit(accountTransaction,invoiceInfo.getId(),null,1,remark,null);
        }
        invoiceInfo.setUpdateTime(new Date());
        invoiceInfo.setUpdateName(sysUser.getUsername());
        invoiceInfo.setIsDelete(1);
        invoiceInfoService.updateById(invoiceInfo);
        iCourseStudentInfoService.updateBatchById(courseStudentList);
    }

    @Override
    public IPage<InvoiceInfo> pageList(InvoiceInfo invoiceInfo, Integer pageNo, Integer pageSize, HttpServletRequest req) {
        Page<InvoiceInfo> page = new Page<InvoiceInfo>(pageNo, pageSize);
        Map<String, String[]> paramMap = req.getParameterMap();
        String order = "desc";
        String column = "id";
        String[] orderArray = paramMap.get("order");
        String[] columArray = paramMap.get("column");
        if(orderArray != null && orderArray.length > 0){
            order = orderArray[0];
        }
        if(columArray != null && columArray.length > 0){
            column = columArray[0];
        }
        return invoiceInfoService.selectInvoicePageList(page,invoiceInfo,order,column);
    }

    @Transactional
    public void updateInvoice(InvoiceAddRequest addRequest){
        //更新invoice信息
        InvoiceInfo invoiceInfo =  invoiceInfoService.getById(addRequest.getId());
        if(invoiceInfo == null){
            throw new RuntimeException(" invoice info is null ");
        }

        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        invoiceInfo.setAmount(addRequest.getSubtotal());
        invoiceInfo.setTax(addRequest.getTax());
        invoiceInfo.setTaxAfterAmount(addRequest.getTaxTotal());
        invoiceInfo.setTaxAmount(addRequest.getTaxTotal().subtract(addRequest.getSubtotal()));
        if(addRequest.getDiscountTotal().compareTo(BigDecimal.ZERO) > 0){
            invoiceInfo.setTaxAmount(invoiceInfo.getTaxAmount().add(addRequest.getDiscountTotal()));
        }
        invoiceInfo.setDiscount(addRequest.getDiscount());
        invoiceInfo.setDiscountType(addRequest.getDiscountType());
        invoiceInfo.setDiscountAmount(addRequest.getDiscountTotal());
        invoiceInfo.setInvoiceAmount(addRequest.getTotal());
        invoiceInfo.setRemarks(addRequest.getRemarks());
        invoiceInfo.setUpdateTime(new Date());
        invoiceInfo.setUpdateName(sysUser.getUsername());
        invoiceInfo.setLastPayTime(addRequest.getLastPayTime());
        invoiceInfo.setCurrencyAmount(addRequest.getCurrencyAmount());
        invoiceInfo.setCurrency(addRequest.getCurrency());
        this.convertLastPayTime(invoiceInfo);
        invoiceInfoService.updateById(invoiceInfo);
        //判断取消操作(编辑时 允许用户取消之前添加的课程)
        courseIsCanccel(invoiceInfo,addRequest.getRecords());
        for(CourseStudentDTO info : addRequest.getRecords()) {
            info.setPayStatus(1);
        }
        //更新course_student_info price 字段
        this.updateCourseStudentInfo(addRequest.getRecords(),invoiceInfo.getId());
    }

    @Transactional
    public void courseIsCanccel(InvoiceInfo invoiceInfo,List<CourseStudentDTO> records){
        List<String> updateIds = records.stream().map(CourseStudentDTO::getId).collect(Collectors.toList());
        List<CourseStudentDTO> cancelDto = new ArrayList<>();
        //加载invoice的课程信息
        CourseStudentSearchVO searchVO = new CourseStudentSearchVO();
        searchVO.setInvoiceId(invoiceInfo.getId());
        List<CourseStudentDTO> courseStudentDTOList =  courseStudentFacade.selectInvoiceCourseStudent(searchVO);
        if(courseStudentDTOList != null && courseStudentDTOList.size() > 0){
            for(CourseStudentDTO info : courseStudentDTOList){
                if(!updateIds.contains(info.getId())){
                    info.setActualPrice(null);
                    info.setPayStatus(0);
                    info.setInvoiceId(null);
                    cancelDto.add(info);
                }
            }
        }
        if(cancelDto.size() > 0){
            this.updateCourseStudentInfo(cancelDto,null);
        }
    }

    @Transactional
    public void updatePayWaringFlag(String lastPayTime){
        log.info( "开始查询最后付款日期为："+lastPayTime + " 的Invoice数据....");
        QueryWrapper<InvoiceInfo> queryWrapper = new QueryWrapper<>();
        List<String>  status =Arrays.asList("0","1");
        queryWrapper.eq("last_pay_time",lastPayTime).in("status",status).eq("is_delete",0);
        List<InvoiceInfo> invoiceInfoList = invoiceInfoService.list(queryWrapper);
        if(invoiceInfoList != null){
            log.info(lastPayTime+"共："+invoiceInfoList.size() + " 条数据");
            for(InvoiceInfo info : invoiceInfoList){
                info.setPayWarningFlag(1);
            }
            invoiceInfoService.updateBatchById(invoiceInfoList);
        }
    }

    /**
     * 付款完成
     * @param request
     */
    @Override
    @Transactional
    public void paymentCompleted(InvoicePaymentCompletedRequest request) {
        log.info("request --> " + JSONUtil.toJsonStr(request));
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        InvoiceInfo info =  invoiceInfoService.getById(request.getId());
       if(info == null){
           throw new RuntimeException(" invoice Object is Null ");
       }
      BigDecimal  actualPriceTotal = BigDecimal.ZERO;
      List<CourseStudentInfo> courseStudentList  = courseStudentFacade.selectByInvoiceId(info.getId(),1);
      if(CollectionUtils.isEmpty(courseStudentList)){
          throw new RuntimeException(" course Student List is Null ");
      }
      //1. 更新 invoice付款状态
      info.setStatus(PaymentStatusEnums.DONE_PAYMENT.getStatus());
      info.setPayWarningFlag(0);
      //2. 更新学生课程 付款状态
      for(CourseStudentInfo sinfo:courseStudentList){
          sinfo.setPayStatus(PaymentStatusEnums.DONE_PAYMENT.getStatus());
          sinfo.setPayTime(new Date());
          sinfo.setUpdateTime(new Date());
          sinfo.setUpdateName(sysUser.getUsername());
          actualPriceTotal = actualPriceTotal.add(sinfo.getActualPrice());
      }
      //3. 增加余额
      BigDecimal invoiceAmount = info.getAmount().add(info.getTaxAmount());
      if(info.getDiscountAmount() != null && info.getDiscountAmount().compareTo(BigDecimal.ZERO) > 0){
          invoiceAmount = invoiceAmount.subtract(info.getDiscountAmount());

          //课程金额 - 折扣金额 = 课程实付金额
          if((info.getAmount().subtract(info.getDiscountAmount())).compareTo(actualPriceTotal) != 0){
              throw new RuntimeException(" subtotal amount is error ");
          }

      }
      if(info.getCredit() != null && info.getCredit() > 0){
          invoiceAmount = invoiceAmount.subtract(new BigDecimal(String.valueOf(info.getCredit())));
      }
      if(info.getInvoiceAmount().compareTo(invoiceAmount) != 0){
          throw new RuntimeException(" invoice amount is error ");
      }
      Integer studentId = courseStudentList.get(0).getStudentId();
      for(CourseStudentInfo sinfo:courseStudentList){
          JSONObject exParam = new JSONObject();
          exParam.put("courseStudentId",sinfo.getId());
          AccountTransaction accountTransaction = new AccountTransaction();
          accountTransaction.setStudentId(studentId);
          accountTransaction.setChangeAmount(sinfo.getActualPrice());
          accountTransaction.setChangeDirection(ChangeDirectionEnums.TYPE_ADD.getType());
          accountTransactionFacade.changeCredit(accountTransaction,info.getId(),sinfo.getCourseId(),0,null, exParam.toJSONString());

          accountTransaction = new AccountTransaction();
          accountTransaction.setStudentId(studentId);
          accountTransaction.setChangeAmount(sinfo.getActualPrice());
          accountTransaction.setChangeDirection(ChangeDirectionEnums.TYPE_FREE.getType());
          accountTransactionFacade.changeCredit(accountTransaction,info.getId(),sinfo.getCourseId(),1,null,exParam.toJSONString());

      }

      info.setUpdateTime(new Date());
      info.setUpdateName(sysUser.getUsername());

      invoiceInfoService.updateById(info);
      iCourseStudentInfoService.updateBatchById(courseStudentList);
    }

    @Transactional
    public void addInvoice(InvoiceAddRequest addRequest){
        if(CollectionUtils.isEmpty(addRequest.getRecords())){
            throw new RuntimeException(" request parameter exception ");
        }
        Set<String> studentIdList = new HashSet<String>();
        addRequest.getRecords().stream().forEach(t -> studentIdList.add(t.getStudentId()));
        if(studentIdList.size() > 1){
            throw new RuntimeException(" Multiple student information cannot exist in Invoice ");
        }
        String studentId = studentIdList.iterator().next();
        //1.添加invoice 对象
        Integer invoiceId = this.saveInvoice(addRequest,Integer.parseInt(studentId));
        for(CourseStudentDTO info : addRequest.getRecords()) {
            info.setPayStatus(1);
        }
        //2.更新course_student_info 付款转台和 price字段
        this.updateCourseStudentInfo(addRequest.getRecords(),invoiceId);
        //3.如果credit > 0 冻结学生账户金额
        if(addRequest.getCredit() != null && addRequest.getCredit() > 0){
            this.freezeAmount(Integer.parseInt(studentId),addRequest.getCredit(),invoiceId);
        }
     }

    @Transactional
    void freezeAmount(Integer studentId, double freezeAmount,Integer invoiceId){
        //AccountTransaction accountTransaction,Integer invoiceId,Integer courseId
        AccountTransaction accountTransaction = new AccountTransaction();
        accountTransaction.setStudentId(studentId);
        accountTransaction.setChangeAmount(new BigDecimal(String.valueOf(freezeAmount)));
        accountTransaction.setChangeDirection(ChangeDirectionEnums.TYPE_FREE.getType());
        String remark="invoice:"+invoiceId + " freeze";
        accountTransactionFacade.changeCredit(accountTransaction,invoiceId,null,0,remark,null);
    }

    @Transactional
    void updateCourseStudentInfo(List<CourseStudentDTO> records,Integer invoiceId){
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        for(CourseStudentDTO info : records){
            CourseStudentInfo  qinfo = courseStudentFacade.selectById(Integer.parseInt(info.getId()));
            if(qinfo != null){
                qinfo.setPayStatus(info.getPayStatus());
                qinfo.setActualPrice(info.getActualPrice());
                qinfo.setInvoiceId(invoiceId);
                qinfo.setUpdateTime(new Date());
                qinfo.setUpdateName(sysUser.getUsername());
                qinfo.setDescription(info.getDescription());
                courseStudentFacade.updateInfo(qinfo);
            }
        }
    }

    @Transactional
    Integer saveInvoice(InvoiceAddRequest addRequest,Integer studentId){
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        InvoiceInfo invoiceInfo = new InvoiceInfo();
        invoiceInfo.setStudentId(studentId);
        invoiceInfo.setAmount(addRequest.getSubtotal());
        invoiceInfo.setTax(addRequest.getTax());
        invoiceInfo.setTaxAfterAmount(addRequest.getTaxTotal());
        invoiceInfo.setTaxAmount(addRequest.getTaxTotal().subtract(addRequest.getSubtotal()));
        if(addRequest.getDiscountTotal().compareTo(BigDecimal.ZERO) > 0){
            invoiceInfo.setTaxAmount(invoiceInfo.getTaxAmount().add(addRequest.getDiscountTotal()));
        }
        invoiceInfo.setDiscount(addRequest.getDiscount());
        invoiceInfo.setDiscountType(addRequest.getDiscountType());
        invoiceInfo.setDiscountAmount(addRequest.getDiscountTotal());
        invoiceInfo.setCredit(addRequest.getCredit());
        invoiceInfo.setInvoiceAmount(addRequest.getTotal());
        invoiceInfo.setRemarks(addRequest.getRemarks());
        invoiceInfo.setStatus(PaymentStatusEnums.ING_PAYMENT.getStatus());
        invoiceInfo.setIsDelete(0);
        invoiceInfo.setCreateTime(new Date());
        invoiceInfo.setUpdateTime(new Date());
        invoiceInfo.setCreateName(sysUser.getUsername());
        invoiceInfo.setUpdateName(sysUser.getUsername());
        invoiceInfo.setInvoiceStatus(0);
        invoiceInfo.setLastPayTime(addRequest.getLastPayTime());
        invoiceInfo.setPayWarningFlag(0);
        invoiceInfo.setCurrency(addRequest.getCurrency());
        invoiceInfo.setCurrencyAmount(addRequest.getCurrencyAmount());
        this.convertLastPayTime(invoiceInfo);
        invoiceInfoService.save(invoiceInfo);
        return invoiceInfo.getId();
    }

    private void convertLastPayTime(InvoiceInfo invoiceInfo){
        if(StringUtils.isNotBlank(invoiceInfo.getLastPayTime())){
            DateTime lastPayTime =  DateUtil.parseDate(invoiceInfo.getLastPayTime());
            long days = DateUtil.between(new Date(),lastPayTime, DateUnit.DAY,false);
            if(days <= 0 ){
                invoiceInfo.setPayWarningFlag(1);
            }else{
                invoiceInfo.setPayWarningFlag(0);
            }
        }
    }
}
